﻿using System;

namespace SkeinLibManaged
{       
    public static partial class ThreeFish
    {
        #region "Core Utilities Specific for 256"
        private static void MIX256(ref UInt64 X1, ref UInt64 Y1, RC256 N1,
                            ref UInt64 X2, ref UInt64 Y2, RC256 N2)
        {   X1 += Y1;   ROTL64(ref Y1, (byte)(N1));     Y1 ^= X1;
            X2 += Y2;   ROTL64(ref Y2, (byte)(N2));     Y2 ^= X2;
        }

        private static void INVMIX256(ref UInt64 X1, ref UInt64 Y1, RC256 N1,
                               ref UInt64 X2, ref UInt64 Y2, RC256 N2)
        {   Y1 ^= X1;   ROTR64(ref Y1, (byte)(N1));     X1 -= Y1;
            Y2 ^= X2;   ROTR64(ref Y2, (byte)(N2));     X2 -= Y2;
        }
        
        private static void KEYI256(UInt64[] k, UInt64[] t, System.Byte round, UInt64[] b)
        {   b[0] += k[(round + 0) % 5];
            b[1] += k[(round + 1) % 5] + t[(round + 0) % 3];
            b[2] += k[(round + 2) % 5] + t[(round + 1) % 3];
            b[3] += k[(round + 3) % 5] + round;
        }

        private static void INVKEYI256(UInt64[] k, UInt64[] t, System.Byte round, UInt64[] b)
        {   b[0] -= (k[(round + 0) % 5]);
            b[1] -= (k[(round + 1) % 5] + t[(round + 0) % 3]);
            b[2] -= (k[(round + 2) % 5] + t[(round + 1) % 3]);
            b[3] -= (k[(round + 3) % 5] + round);
        }
        #endregion

        /// <summary>
        /// Transform four 64-bit words according to ThreeFish algorithm.
        /// </summary>
        /// <param name="input">The four 64-bit words to be transformed.</param>
        /// <param name="key">The four 64-bit key words used during the transformation.</param>
        /// <param name="tweak">The two 64-bit tweak words used in conjunction with the key.</param>
        /// <param name="feed">False for encryption, true for hashing mechanism used by Skein.</param>
        /// <returns>Array of four 64-bit tranformed words.</returns>
        public static UInt64[] ThreeFish256Words(
                    UInt64[] input, UInt64[] key, UInt64[] tweak, System.Boolean feed)
        {
            //Error checking!
            if (input == null)
                throw new System.ArgumentNullException("ThreeFish256Words: Input cannot be null!");
            if (key == null)
                throw new System.ArgumentNullException("ThreeFish256Words: Key cannot be null!");
            if (tweak == null)
                throw new System.ArgumentNullException("ThreeFish256Words: Tweak cannot be null!");
            if (input.Length != 4)
                throw new System.ArgumentException("ThreeFish256Words: Incorrect length for input word array.");
            if (key.Length != 4)
                throw new System.ArgumentException("ThreeFish256Words: Incorrect length for key word array.");
            if (tweak.Length != 2)
                throw new System.ArgumentException("ThreeFish256Words: Incorrect length for tweak word array.");
            UInt64[] buf = {input[0], input[1], input[2], input[3]};
            UInt64[] locKey = {key[0], key[1], key[2], key[3], 
                               UNIQUE_K(key)};
            UInt64[] locTweak = {tweak[0], tweak[1], (tweak[0] ^ tweak[1])};
            UInt64[] locFeed = null;
            if (feed == true)
            {   locFeed = new UInt64[] {input[0], input[1], input[2], input[3]};
            };
            
            KEYI256(locKey, locTweak, 0, buf);
	        MIX256(ref buf[0],ref buf[1],RC256.R0A,ref buf[2],ref buf[3],RC256.R0B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R1A,ref buf[2],ref buf[1],RC256.R1B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R2A,ref buf[2],ref buf[3],RC256.R2B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R3A,ref buf[2],ref buf[1],RC256.R3B);
            KEYI256(locKey, locTweak, 1, buf);	
	        MIX256(ref buf[0],ref buf[1],RC256.R4A,ref buf[2],ref buf[3],RC256.R4B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R5A,ref buf[2],ref buf[1],RC256.R5B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R6A,ref buf[2],ref buf[3],RC256.R6B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R7A,ref buf[2],ref buf[1],RC256.R7B);
            KEYI256(locKey, locTweak, 2, buf);
	        MIX256(ref buf[0],ref buf[1],RC256.R0A,ref buf[2],ref buf[3],RC256.R0B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R1A,ref buf[2],ref buf[1],RC256.R1B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R2A,ref buf[2],ref buf[3],RC256.R2B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R3A,ref buf[2],ref buf[1],RC256.R3B);
            KEYI256(locKey, locTweak, 3, buf);
	        MIX256(ref buf[0],ref buf[1],RC256.R4A,ref buf[2],ref buf[3],RC256.R4B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R5A,ref buf[2],ref buf[1],RC256.R5B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R6A,ref buf[2],ref buf[3],RC256.R6B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R7A,ref buf[2],ref buf[1],RC256.R7B);
            KEYI256(locKey, locTweak, 4, buf);
	        MIX256(ref buf[0],ref buf[1],RC256.R0A,ref buf[2],ref buf[3],RC256.R0B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R1A,ref buf[2],ref buf[1],RC256.R1B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R2A,ref buf[2],ref buf[3],RC256.R2B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R3A,ref buf[2],ref buf[1],RC256.R3B);
            KEYI256(locKey, locTweak, 5, buf);
	        MIX256(ref buf[0],ref buf[1],RC256.R4A,ref buf[2],ref buf[3],RC256.R4B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R5A,ref buf[2],ref buf[1],RC256.R5B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R6A,ref buf[2],ref buf[3],RC256.R6B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R7A,ref buf[2],ref buf[1],RC256.R7B);
            KEYI256(locKey, locTweak, 6, buf);
	        MIX256(ref buf[0],ref buf[1],RC256.R0A,ref buf[2],ref buf[3],RC256.R0B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R1A,ref buf[2],ref buf[1],RC256.R1B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R2A,ref buf[2],ref buf[3],RC256.R2B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R3A,ref buf[2],ref buf[1],RC256.R3B);
            KEYI256(locKey, locTweak, 7, buf);	
	        MIX256(ref buf[0],ref buf[1],RC256.R4A,ref buf[2],ref buf[3],RC256.R4B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R5A,ref buf[2],ref buf[1],RC256.R5B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R6A,ref buf[2],ref buf[3],RC256.R6B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R7A,ref buf[2],ref buf[1],RC256.R7B);
            KEYI256(locKey, locTweak, 8, buf);
	        MIX256(ref buf[0],ref buf[1],RC256.R0A,ref buf[2],ref buf[3],RC256.R0B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R1A,ref buf[2],ref buf[1],RC256.R1B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R2A,ref buf[2],ref buf[3],RC256.R2B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R3A,ref buf[2],ref buf[1],RC256.R3B);
            KEYI256(locKey, locTweak, 9, buf);
	        MIX256(ref buf[0],ref buf[1],RC256.R4A,ref buf[2],ref buf[3],RC256.R4B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R5A,ref buf[2],ref buf[1],RC256.R5B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R6A,ref buf[2],ref buf[3],RC256.R6B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R7A,ref buf[2],ref buf[1],RC256.R7B);
            KEYI256(locKey, locTweak, 10, buf);
	        MIX256(ref buf[0],ref buf[1],RC256.R0A,ref buf[2],ref buf[3],RC256.R0B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R1A,ref buf[2],ref buf[1],RC256.R1B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R2A,ref buf[2],ref buf[3],RC256.R2B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R3A,ref buf[2],ref buf[1],RC256.R3B);
            KEYI256(locKey, locTweak, 11, buf);	
	        MIX256(ref buf[0],ref buf[1],RC256.R4A,ref buf[2],ref buf[3],RC256.R4B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R5A,ref buf[2],ref buf[1],RC256.R5B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R6A,ref buf[2],ref buf[3],RC256.R6B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R7A,ref buf[2],ref buf[1],RC256.R7B);
            KEYI256(locKey, locTweak, 12, buf);
	        MIX256(ref buf[0],ref buf[1],RC256.R0A,ref buf[2],ref buf[3],RC256.R0B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R1A,ref buf[2],ref buf[1],RC256.R1B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R2A,ref buf[2],ref buf[3],RC256.R2B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R3A,ref buf[2],ref buf[1],RC256.R3B);
            KEYI256(locKey, locTweak, 13, buf);	
	        MIX256(ref buf[0],ref buf[1],RC256.R4A,ref buf[2],ref buf[3],RC256.R4B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R5A,ref buf[2],ref buf[1],RC256.R5B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R6A,ref buf[2],ref buf[3],RC256.R6B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R7A,ref buf[2],ref buf[1],RC256.R7B);
            KEYI256(locKey, locTweak, 14, buf);
	        MIX256(ref buf[0],ref buf[1],RC256.R0A,ref buf[2],ref buf[3],RC256.R0B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R1A,ref buf[2],ref buf[1],RC256.R1B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R2A,ref buf[2],ref buf[3],RC256.R2B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R3A,ref buf[2],ref buf[1],RC256.R3B);
            KEYI256(locKey, locTweak, 15, buf);	
	        MIX256(ref buf[0],ref buf[1],RC256.R4A,ref buf[2],ref buf[3],RC256.R4B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R5A,ref buf[2],ref buf[1],RC256.R5B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R6A,ref buf[2],ref buf[3],RC256.R6B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R7A,ref buf[2],ref buf[1],RC256.R7B);
            KEYI256(locKey, locTweak, 16, buf);
	        MIX256(ref buf[0],ref buf[1],RC256.R0A,ref buf[2],ref buf[3],RC256.R0B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R1A,ref buf[2],ref buf[1],RC256.R1B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R2A,ref buf[2],ref buf[3],RC256.R2B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R3A,ref buf[2],ref buf[1],RC256.R3B);
            KEYI256(locKey, locTweak, 17, buf);	
	        MIX256(ref buf[0],ref buf[1],RC256.R4A,ref buf[2],ref buf[3],RC256.R4B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R5A,ref buf[2],ref buf[1],RC256.R5B);	
	        MIX256(ref buf[0],ref buf[1],RC256.R6A,ref buf[2],ref buf[3],RC256.R6B);	
	        MIX256(ref buf[0],ref buf[3],RC256.R7A,ref buf[2],ref buf[1],RC256.R7B);
            KEYI256(locKey, locTweak, 18, buf);

	        for (byte i = 0; i < 4; i++)
            {   if (feed == true)   buf[i] ^= locFeed[i];
            }
            return buf;
        }

        /// <summary>
        /// If the ThreeFish256Words transformation was done with "feed" = false, the words can be "untransformed" with the
        /// SAME key AND tweak using this function.
        /// </summary>
        /// <param name="input">The four 64-bit key words to be recovered.</param>
        /// <param name="key">The four 64-bit key words used during the transformation.</param>
        /// <param name="tweak">The two 64-bit tweak words used in conjunction with the key.</param>
        /// <returns>Array of four 64-bit untranformed words.</returns>
        public static UInt64[] InvThreeFish256Words(
                    UInt64[] input, UInt64[] key, UInt64[] tweak)
        {
            //Error checking!
            if (input == null)
                throw new System.ArgumentNullException("InvThreeFish256Words: Input cannot be null!");
            if (key == null)
                throw new System.ArgumentNullException("InvThreeFish256Words: Key cannot be null!");
            if (tweak == null)
                throw new System.ArgumentNullException("InvThreeFish256Words: Tweak cannot be null!");
            if (input.Length != 4)
                throw new System.ArgumentException("InvThreeFish256Words: Incorrect length for input word array.");
            if (key.Length != 4)
                throw new System.ArgumentException("InvThreeFish256Words: Incorrect length for key word array.");
            if (tweak.Length != 2)
                throw new System.ArgumentException("InvThreeFish256Words: Incorrect length for tweak word array.");
            UInt64[] buf = { input[0], input[1], input[2], input[3] };
            UInt64[] locKey = { key[0], key[1], key[2], key[3], UNIQUE_K(key) };
            UInt64[] locTweak = { tweak[0], tweak[1], (tweak[0] ^ tweak[1]) };

            INVKEYI256(locKey, locTweak, 18, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R7A, ref buf[2], ref buf[1], RC256.R7B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R6A, ref buf[2], ref buf[3], RC256.R6B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R5A, ref buf[2], ref buf[1], RC256.R5B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R4A, ref buf[2], ref buf[3], RC256.R4B);
            INVKEYI256(locKey, locTweak, 17, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R3A, ref buf[2], ref buf[1], RC256.R3B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R2A, ref buf[2], ref buf[3], RC256.R2B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R1A, ref buf[2], ref buf[1], RC256.R1B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R0A, ref buf[2], ref buf[3], RC256.R0B);
            INVKEYI256(locKey, locTweak, 16, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R7A, ref buf[2], ref buf[1], RC256.R7B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R6A, ref buf[2], ref buf[3], RC256.R6B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R5A, ref buf[2], ref buf[1], RC256.R5B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R4A, ref buf[2], ref buf[3], RC256.R4B);
            INVKEYI256(locKey, locTweak, 15, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R3A, ref buf[2], ref buf[1], RC256.R3B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R2A, ref buf[2], ref buf[3], RC256.R2B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R1A, ref buf[2], ref buf[1], RC256.R1B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R0A, ref buf[2], ref buf[3], RC256.R0B);
            INVKEYI256(locKey, locTweak, 14, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R7A, ref buf[2], ref buf[1], RC256.R7B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R6A, ref buf[2], ref buf[3], RC256.R6B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R5A, ref buf[2], ref buf[1], RC256.R5B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R4A, ref buf[2], ref buf[3], RC256.R4B);
            INVKEYI256(locKey, locTweak, 13, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R3A, ref buf[2], ref buf[1], RC256.R3B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R2A, ref buf[2], ref buf[3], RC256.R2B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R1A, ref buf[2], ref buf[1], RC256.R1B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R0A, ref buf[2], ref buf[3], RC256.R0B);
            INVKEYI256(locKey, locTweak, 12, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R7A, ref buf[2], ref buf[1], RC256.R7B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R6A, ref buf[2], ref buf[3], RC256.R6B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R5A, ref buf[2], ref buf[1], RC256.R5B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R4A, ref buf[2], ref buf[3], RC256.R4B);
            INVKEYI256(locKey, locTweak, 11, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R3A, ref buf[2], ref buf[1], RC256.R3B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R2A, ref buf[2], ref buf[3], RC256.R2B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R1A, ref buf[2], ref buf[1], RC256.R1B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R0A, ref buf[2], ref buf[3], RC256.R0B);
            INVKEYI256(locKey, locTweak, 10, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R7A, ref buf[2], ref buf[1], RC256.R7B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R6A, ref buf[2], ref buf[3], RC256.R6B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R5A, ref buf[2], ref buf[1], RC256.R5B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R4A, ref buf[2], ref buf[3], RC256.R4B);
            INVKEYI256(locKey, locTweak, 9, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R3A, ref buf[2], ref buf[1], RC256.R3B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R2A, ref buf[2], ref buf[3], RC256.R2B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R1A, ref buf[2], ref buf[1], RC256.R1B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R0A, ref buf[2], ref buf[3], RC256.R0B);
            INVKEYI256(locKey, locTweak, 8, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R7A, ref buf[2], ref buf[1], RC256.R7B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R6A, ref buf[2], ref buf[3], RC256.R6B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R5A, ref buf[2], ref buf[1], RC256.R5B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R4A, ref buf[2], ref buf[3], RC256.R4B);
            INVKEYI256(locKey, locTweak, 7, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R3A, ref buf[2], ref buf[1], RC256.R3B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R2A, ref buf[2], ref buf[3], RC256.R2B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R1A, ref buf[2], ref buf[1], RC256.R1B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R0A, ref buf[2], ref buf[3], RC256.R0B);
            INVKEYI256(locKey, locTweak, 6, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R7A, ref buf[2], ref buf[1], RC256.R7B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R6A, ref buf[2], ref buf[3], RC256.R6B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R5A, ref buf[2], ref buf[1], RC256.R5B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R4A, ref buf[2], ref buf[3], RC256.R4B);
            INVKEYI256(locKey, locTweak, 5, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R3A, ref buf[2], ref buf[1], RC256.R3B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R2A, ref buf[2], ref buf[3], RC256.R2B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R1A, ref buf[2], ref buf[1], RC256.R1B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R0A, ref buf[2], ref buf[3], RC256.R0B);
            INVKEYI256(locKey, locTweak, 4, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R7A, ref buf[2], ref buf[1], RC256.R7B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R6A, ref buf[2], ref buf[3], RC256.R6B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R5A, ref buf[2], ref buf[1], RC256.R5B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R4A, ref buf[2], ref buf[3], RC256.R4B);
            INVKEYI256(locKey, locTweak, 3, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R3A, ref buf[2], ref buf[1], RC256.R3B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R2A, ref buf[2], ref buf[3], RC256.R2B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R1A, ref buf[2], ref buf[1], RC256.R1B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R0A, ref buf[2], ref buf[3], RC256.R0B);
            INVKEYI256(locKey, locTweak, 2, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R7A, ref buf[2], ref buf[1], RC256.R7B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R6A, ref buf[2], ref buf[3], RC256.R6B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R5A, ref buf[2], ref buf[1], RC256.R5B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R4A, ref buf[2], ref buf[3], RC256.R4B);
            INVKEYI256(locKey, locTweak, 1, buf);
            INVMIX256(ref buf[0], ref buf[3], RC256.R3A, ref buf[2], ref buf[1], RC256.R3B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R2A, ref buf[2], ref buf[3], RC256.R2B);
            INVMIX256(ref buf[0], ref buf[3], RC256.R1A, ref buf[2], ref buf[1], RC256.R1B);
            INVMIX256(ref buf[0], ref buf[1], RC256.R0A, ref buf[2], ref buf[3], RC256.R0B);
            INVKEYI256(locKey, locTweak, 0, buf);

            return buf;
        }
    }
}
